﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SnmpWorkshop.Communication 
{
using System.Net; 
using System.Net.Sockets; 

using SnmpWorkshop.Tools;

using Lextm.SharpSnmpLib;
using Lextm.SharpSnmpLib.Messaging;
using Lextm.SharpSnmpLib.Security;

  public abstract class SnmpAgentBase
  {
    protected UserRegistry userRegistry;
    public void Configure()
    {
      this.userRegistry= new UserRegistry();
      this.userRegistry.Add( new User( new OctetString( "alamakota"), DefaultPrivacyProvider.DefaultPair));
    }

    public delegate void OnUdpMessageOutHandler( IPEndPoint remoteIPEndPoint, byte[] _byteBuffer);
    public event OnUdpMessageOutHandler OnUdpMessageOut;

    IPEndPoint remoteIPEndPoint;
    public void OnUdpMessageInHandler( IPEndPoint _remoteIPEndPoint, byte[] _byteBuffer ) 
    {
      HandyLogClient.Write( "SnmpAgentBase", String.Format( "{0} bytes received", _byteBuffer.Length));

      IList<ISnmpMessage> messageList= MessageFactory.ParseMessages( _byteBuffer, userRegistry);

      this.remoteIPEndPoint= _remoteIPEndPoint;
      this.snmpMessageHandler( messageList[ 0]);  

      //if( this.OnUdpMessageOut!= null)
      //{
      //  HandyLogClient.Write( "SnmpAgentBase", String.Format( "{0} bytes sent", _byteBuffer.Length));
      //  this.OnUdpMessageOut( _remoteIPEndPoint, _byteBuffer);
      //}
    }

    protected abstract void snmpMessageHandler( ISnmpMessage _message);    

    protected void sendSnmpMessage( ISnmpMessage _message)
    {
      this.OnUdpMessageOut( this.remoteIPEndPoint, _message.ToBytes());
    }
  }

  public class UdpSkeleton
  {
    private int localUdpPort= 7;
    private UdpClient localUdpClient= null;

    public delegate void OnUdpMessageInHandler( IPEndPoint remoteIPEndPoint, byte[] buffer);
    public event OnUdpMessageInHandler OnMessageIn;

    public void OnUdpMessageOutHandler( IPEndPoint _remoteIPEndPoint, byte[] _byteBuffer)
    {
      try 
      {
         this.localUdpClient.Send( _byteBuffer, _byteBuffer.Length, _remoteIPEndPoint);
      }
      
      catch( Exception _excp)
      {
         HandyLogClient.Write( "OnUdpMessageOutHandler", _excp.Message);
      }
    }

    public void Configure( string[] _args) 
    {
      if( _args.Length != 1) 
      { 
        throw new ArgumentException("Parameters: <Port>");
      }

      this.localUdpPort= ( _args.Length== 1) ? Int32.Parse( _args[0]) : 7;
      try 
      {
        // Create an instance of UdpClient on the port to listen on
        this.localUdpClient= new UdpClient( this.localUdpPort);   
        HandyLogClient.Write( "UdpSkeleton", String.Format( "connected to local udp port {0}", this.localUdpPort));
      } 

      catch( SocketException _se) 
      {
        HandyLogClient.Write( "UdpSkeleton", _se.ErrorCode + ": " + _se.Message);     
        Environment.Exit( _se.ErrorCode);
      }
    }  

    public void Run() 
    {
      // Create an IPEndPoint instance that will be passed as a reference
      // to the Receive() call and be populated with the remote client info
      IPEndPoint remoteIPEndPoint= new IPEndPoint( IPAddress.Any, 0);

      for (;;) 
      { // Run forever, receiving and echoing datagrams
        try 
        {
          byte[] byteBuffer= this.localUdpClient.Receive( ref remoteIPEndPoint);

          HandyLogClient.Write( "UdpSkeleton", String.Format("{0} bytes received", byteBuffer.Length));

          if( this.OnMessageIn!= null)
            this.OnMessageIn( remoteIPEndPoint, byteBuffer);
        } 
        catch ( SocketException se) 
        {
          System.Console.WriteLine(se.ErrorCode + ": " + se.Message);
        }
      }
    }
  }
}
